//
//  SEGBasicWKWebViewController.m
//  SEGWebView
//
//  Created by 山刘 on 2020/3/16.
//

#import "SEGBasicWKWebViewController.h"
#import "SEGWebViewConsts.h"
#import "NSString+WKAdd.h"
#import "SEGBasicWKWebViewCookieManager.h"

@interface SEGBasicWKWebViewController ()
@end

@implementation SEGBasicWKWebViewController
#pragma mark - 生命周期
- (void)viewDidLoad {
    self.view.backgroundColor = UIColor.whiteColor;
    [super viewDidLoad];
}

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    //防止白屏问题
    if (!self.webView.title) {
        [self.webView reload];
    }
}

- (void)dealloc{
    [self.webView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
}

#pragma mark - 数据加载、刷新
/// 加载网页数据
-(NSString*)loadDataWithURLString:(NSString*)urlString{
    self.isHideHeader = ([urlString rangeOfString:@"isHideHeader=1"].location != NSNotFound);
    self.agreement = ([urlString rangeOfString:@"/h5/agreement/index.html"].location != NSNotFound);
    
    urlString = [self segReplaceUrlStringWithUrlString:urlString];
    urlString = [self getUrlStringWithAppPlatformCode:urlString];
    
    [SEGBasicWKWebViewCookieManager syncCookieThenLoadWeb:self.webView url:[NSURL URLWithString:urlString]];
    
    return urlString;
}

/// 加载网页支付 cbUrl
-(void)loadCbUrlString {
    if (self.cbUrlString && self.cbUrlString.length > 0) {
        
        // 会回退到首页
        //[self.webView stopLoading];
        //WKBackForwardListItem * firstBackItem = self.webView.backForwardList.backList.firstObject;
        //if (firstBackItem) [self.webView goToBackForwardListItem:firstBackItem];
        
        [self loadDataWithURLString:self.cbUrlString];
        self.cbUrlString = @"";
    }
}

#pragma mark - 私有方法
/// 更新进度条
-(void)updateProgress:(CGFloat)value {
    if ([self isShowProgressView]) {
        self.progressView.progress = value;
        [self.progressView setHidden: (value > 0 && value < 1) ? NO : YES];
    }else{
        [self.progressView setHidden:YES];
    }
}

#pragma mark - KVO
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.webView){
        [self updateProgress:self.webView.estimatedProgress];
        if (self.webView.estimatedProgress >= 1.0f) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self updateProgress:0];
            });
        }
    }else{
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

#pragma mark - WKScriptMessageHandler
/// 捕捉H5通过'window.webkit.messageHandlers'唤起原生方法。
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
}

#pragma mark - WKNavigationDelegate
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
    NSString *urlString = [navigationAction.request.URL.absoluteString wkStringByURLDecode];
    NSLog(@"✨✨✨%@",urlString);
    self.currentUrl = webView.URL;
    
    NSString * scheme = navigationAction.request.URL.scheme;
    NSString * host = navigationAction.request.URL.host;
    NSString * query = [navigationAction.request.URL.query wkStringByURLDecode];
    
    if ([navigationAction.request.URL.absoluteString rangeOfString:@"params="].location != NSNotFound) {
        query = [[navigationAction.request.URL.absoluteString componentsSeparatedByString:@"params="].lastObject wkStringByURLDecode];
    }
    
    //打电话
    if ([scheme isEqualToString:@"tel"]) {
        NSString *resourceSpecifier = [navigationAction.request.URL resourceSpecifier];
        NSMutableString* str = [[NSMutableString alloc] initWithFormat:@"tel:%@", resourceSpecifier];
        [[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    
    // 基于：window.location.href拦截JS协议，唤起原生方法
    if (scheme && host && [scheme rangeOfString:@"uhomeoc"].location != NSNotFound){
        self.current_uhomeoc_href = navigationAction.request.URL;
    }
    
    // 子类调用的方法，实现与业务挂钩
    if ([self jsInvokeSystemFunctionWithWebView:webView request:navigationAction.request query:query] == NO) {
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    
    decisionHandler(WKNavigationActionPolicyAllow);
    return;
}

// 根据客户端受到的服务器响应头以及response相关信息来决定是否可以跳转
-(void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    decisionHandler(WKNavigationResponsePolicyAllow);
}
//进程被终止时调用
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
    // 防止白屏问题
    [webView reload];
}

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
    NSString *injectionJSString = @"var script = document.createElement('meta');"
    "script.name = 'viewport';"
    "script.content=\"width=device-width, user-scalable=no\";"
    "document.getElementsByTagName('head')[0].appendChild(script);";
    [webView evaluateJavaScript:injectionJSString completionHandler:nil];
}

-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    NSLog(@"%s",__FUNCTION__);
    [self updateProgress:0.0F];
    //[self requestFailWithWebView:webView didFailProvisionalNavigation:navigation withError:error];
}

-(void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    [self updateProgress:0.0F];
    //[self requestFailWithWebView:webView didFailProvisionalNavigation:navigation withError:error];
    NSLog(@"%s,reason:%@",__FUNCTION__,error.localizedDescription);
}

#pragma mark - WKUIDelegate

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }]];
    [self presentViewController:alert animated:YES completion:nil];
}
// 确认框
//JavaScript调用confirm方法后回调的方法 confirm是js中的确定框，需要在block中把用户选择的情况传递进去
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
    
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleActionSheet];
    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }]];
    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }]];
    [self presentViewController:alert animated:YES completion:nil];
}
// 输入框
//JavaScript调用prompt方法后回调的方法 prompt是js中的输入框 需要在block中把用户输入的信息传入
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.text = defaultText;
    }];
    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(alertController.textFields[0].text?:@"");
    }])];
    [self presentViewController:alertController animated:YES completion:nil];
}

-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{
    
    //解决WKWebView不能打开任何有target="_blank"（开一个新的窗口）属性的网页
    if (!navigationAction.targetFrame.isMainFrame) {
        [webView loadRequest:navigationAction.request];
    }
    
    return nil;
}

#pragma mark - 父类方法
-(void)segAddSubview {
    if (@available(iOS 11.0, *)) {
        self.webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    }else {
        self.automaticallyAdjustsScrollViewInsets = NO;
    }
    
    [self.view addSubview:self.webView];
    [self.webView addSubview:self.progressView];
    
}

-(void)segAddKVO{
     [self.webView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:nil];
}

-(void)segAddNotifications{
}

-(BOOL)jsInvokeSystemFunctionWithWebView:(WKWebView *)webView request:(NSURLRequest *)request query:(NSString *)query{
    return YES;
}
-(NSString*)segReplaceUrlStringWithUrlString:(NSString *)urlString {
    return urlString;
}
-(NSString*)getUrlStringWithAppPlatformCode:(NSString *)urlString {
    return urlString;
}
/// 是否展示进度条，默认NO。
-(BOOL)isShowProgressView{
    return NO;
}

/**
 网络请求失败
 
 @author Sam
 */
-(void)requestFailWithWebView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
}

#pragma mark - cookie相关

#pragma mark - 私有方法

#pragma mark - getter
-(WKWebView *)webView{
    if(_webView == nil){
        //创建网页配置对象
        WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        
        // 是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放
        config.allowsInlineMediaPlayback = YES;
        //设置视频是否需要用户手动播放  设置为NO则会允许自动播放
        if (@available(iOS 9.0, *)) {
            config.requiresUserActionForMediaPlayback = YES;
        } else {
            // Fallback on earlier versions
        }
        
        //设置是否允许画中画技术 在特定设备上有效
        if (@available(iOS 9.0, *)) {
            config.allowsPictureInPictureMediaPlayback = YES;
        } else {
            // Fallback on earlier versions
        }
        
        // 针对iOS8～iOS10 cookie注入的方案
        __block NSMutableArray*tmp = [NSMutableArray array];
        NSArray<NSHTTPCookie *> * cookies = [[NSHTTPCookieStorage  sharedHTTPCookieStorage] cookies];
        [cookies enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            [tmp addObject:[NSString stringWithFormat:@"document.cookie = '%@=%@'",obj.name,obj.value]];
        }];
        WKUserContentController* userContentController = [[WKUserContentController alloc] init];
        WKUserScript * cookieScript = [[WKUserScript alloc]initWithSource:[tmp componentsJoinedByString:@";"] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
        [userContentController addUserScript:cookieScript];
        config.userContentController = userContentController;
        
        // 创建设置对象
        WKPreferences *preference = [[WKPreferences alloc]init];
        //最小字体大小 当将javaScriptEnabled属性设置为NO时，可以看到明显的效果
        preference.minimumFontSize = 0;
        //设置是否支持javaScript 默认是支持的
        preference.javaScriptEnabled = YES;
        // 在iOS上默认为NO，表示是否允许不经过用户交互由javaScript自动打开窗口
        preference.javaScriptCanOpenWindowsAutomatically = YES;
        config.preferences = preference;
        
        //以下代码适配文本大小：scalesPageToFit
        NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
        //用于进行JavaScript注入
        WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
        [config.userContentController addUserScript:wkUScript];
        
        _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, WK_SCREEN_WIDTH(), WK_SCREEN_HEIGHT()) configuration:config];
        _webView.UIDelegate = self;
        _webView.navigationDelegate = self;
        _webView.allowsBackForwardNavigationGestures = YES;// 是否允许手势左滑返回上一级, 类似导航控制的左滑返回
        
        //设置请求的User-Agent信息中应用程序名称 iOS9后可用
        [_webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
            NSString *userAgent = result;
            NSString *newUserAgent = [userAgent stringByAppendingString:@"/uhome_iPhone"];
            
            NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:newUserAgent, @"UserAgent", nil];
            [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
            [[NSUserDefaults standardUserDefaults] synchronize];
            
            if (@available(iOS 9.0, *)) {
                [self->_webView setCustomUserAgent:newUserAgent];
            } else {
                [self->_webView setValue:newUserAgent forKey:@"applicationNameForUserAgent"];
            }
        }];
    }
    return _webView;
}

-(UIProgressView *)progressView{
    if (!_progressView) {
        _progressView = [[UIProgressView alloc] initWithFrame:CGRectZero];
        [_progressView setHidden:YES];
    }
    return _progressView;
}
@end
